package gsw.tool.pluggable.pm;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Binder;
import android.os.RemoteException;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import gsw.tool.pluggable.pm.parser.PackageMapPlugin;
import gsw.tool.pluggable.IPluiginManager;
import gsw.tool.pluggable.am.ActivityManageService;
import gsw.tool.pluggable.utils.reflect.FileUtils;
import gsw.tool.pluggable.utils.reflect.PluginDirHelper;

/**
 * 自定义的PMS，管理宿主中需要加载的插件，运行在PluginManagerService中。
 * 主要用来管理插件APK的安装、卸载、包信息查询等。
 */
public class MPackageManager extends IPluiginManager.Stub {
    //PMS服务的上下文
    private Context context;
    //自定义的AMS
    ActivityManageService AMS;
    //缓存插件APK的包信息
    private Map<String, PackageMapPlugin> pluginAllMap = new HashMap<>(20);

    public MPackageManager(Context context) {
        this.context = context;
        this.AMS = new ActivityManageService(context);
        init();
    }

    /**
     * 初始化PMS
     */
    private void init() {
        new Thread() {
            @Override
            public void run() {
                super.run();
                onCreate();
            }
        }.start();
    }

    /**
     * 初始化PMS,获取插件的包信息
     */
    private void onCreate() {
        //插件APK文件
        ArrayList<File> apkfiles = null;
        try {
            apkfiles = new ArrayList<File>();
            /**
             * 获取插件APK的目录：插件APK放在统一的目录下,即/data/data/宿主包名/Plugin/
             * 插件apk的存放格式：/data/data/宿主包名/Plugin/插件包名/apk/base.apk
             */
            File baseDir = new File(PluginDirHelper.getBaseDir(context));
            File[] dirs = baseDir.listFiles();
            //遍历插件目录，获取插件APK文件
            for (File dir : dirs) {
                if (dir.isDirectory()) {
                    File file = new File(dir, "apk/base.apk");
                    if (file.exists()) {
                        apkfiles.add(file);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //遍历插件APK文件，缓存其四大组件的信息
        if (apkfiles != null && apkfiles.size() > 0) {
            for (File pluginFile : apkfiles) {
                try {
                    PackageMapPlugin pluginPackageMap = new PackageMapPlugin(context, pluginFile);
                    pluginAllMap.put(pluginPackageMap.getmPackageName(), pluginPackageMap);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 安装插件APK
     *
     * @param pluginFile 插件APK文件
     * @param flags      标志位
     * @return 安装结果：0代表成功，-1代表失败，1代表已经加载到内存了
     */
    @Override
    public int installPackage(String pluginFile, int flags) throws RemoteException {
        /**
         * 模拟系统安装APK，将插件APK放入宿主的指定目录下
         */
        android.content.pm.PackageManager pm = context.getPackageManager();
        //获取插件APK的包信息
        PackageInfo info = pm.getPackageArchiveInfo(pluginFile, 0);

        /**
         * 如果插件APK已经加载了，就不再重复加载，否则会出现异常
         */
        if (pluginAllMap.get(info.packageName) != null) {
            return 1;
        }

        //获取插件APK的存放路径:/data/user/0/宿主包名/Plugin/插件包名/apk/base.apk
        String apkfile = PluginDirHelper.getPluginApkFile(context, info.packageName);
        //删除旧的插件APK文件
        if (new File(apkfile).exists()) {
            new File(apkfile).delete();
        }
        //将插件APK文件放入指定位置
        FileUtils.copyFile(pluginFile, apkfile);

        /**
         * 解析插件APK文件，缓存其四大组件的信息
         */
        try {
            PackageMapPlugin pluginPackageMap = new PackageMapPlugin(context, new File(apkfile));
            pluginAllMap.put(pluginPackageMap.getmPackageName(), pluginPackageMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 卸载插件APK,根据插件包名卸载
     *
     * @param packageName 插件包名
     * @param flags       标志位
     * @return 卸载结果：0代表成功，-1代表失败
     */
    @Override
    public int deletePackage(String packageName, int flags) throws RemoteException {
        //根据插件包名从缓存中移除
        if (pluginAllMap.get(packageName) != null) {
            pluginAllMap.remove(packageName);
        }

        //获取插件APK的存放路径:/data/user/0/宿主包名/Plugin/插件包名/apk/base.apk
        String apkfile = PluginDirHelper.getPluginApkFile(context, packageName);
        //删除插件APK文件
        if (new File(apkfile).exists()) {
            new File(apkfile).delete();
            return 0;
        }
        return -1;
    }

    /**
     * 根据插件APK的包名获取插件的包信息
     *
     * @param packageName 包名
     * @param flags       标志位
     * @return 插件的包信息
     */
    @Override
    public ApplicationInfo getApplicationInfo(String packageName, int flags) throws RemoteException {
        PackageMapPlugin prase = pluginAllMap.get(packageName);
        try {
            return prase.getApplicationInfo(0);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据插件的组件名获取插件组件的存档信息
     *
     * @param className 插件的组件名
     * @param flags     标志位
     * @return 插件组件的存档信息
     */
    @Override
    public ActivityInfo getActivityInfo(ComponentName className, int flags) throws RemoteException {
        //根据包名从插件管理器中获取包信息
        PackageMapPlugin pluginPackageMap = pluginAllMap.get(className.getPackageName());
        if (pluginPackageMap != null) {
            try {
                return pluginPackageMap.getActivityInfo(className, flags);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 根据插件组件的意图获取代理组件的ActivityInfo
     *
     * @param targetIntent 插件组件的意图
     * @return 代理组件的ActivityInfo
     */
    @Override
    public ActivityInfo selectStubActivityInfoByIntent(Intent targetIntent) throws RemoteException {
        ActivityInfo ai = getActivityInfo(targetIntent.getComponent(), 0);
        if (ai != null) {
            return AMS.selectStubActivityInfo(Binder.getCallingPid(), Binder.getCallingUid(), ai);
        } else {
            return null;
        }
    }

    /**
     * 开启代理组件的进程时，初始自定义AMS中的代理进程的信息
     *
     * @param stubProcessName   代理进程名
     * @param targetProcessName 目标进程名
     * @param targetPkg         目标包名
     */
    @Override
    public void onOpenPluginProcess(String stubProcessName, String targetProcessName, String targetPkg) throws RemoteException {
        AMS.onOpenPluginProcess(Binder.getCallingPid(), Binder.getCallingUid(), stubProcessName, targetProcessName, targetPkg);
    }

    @Override
    public boolean waitForReady() throws RemoteException {
        return false;
    }

    @Override
    public PackageInfo getPackageInfo(String packageName, int flags) throws RemoteException {
        return null;
    }

    @Override
    public boolean isPluginPackage(String packageName) throws RemoteException {
        return false;
    }

    @Override
    public ActivityInfo getReceiverInfo(ComponentName className, int flags) throws RemoteException {
        return null;
    }

    @Override
    public ServiceInfo getServiceInfo(ComponentName className, int flags) throws RemoteException {
        return null;
    }

    @Override
    public ProviderInfo getProviderInfo(ComponentName className, int flags) throws RemoteException {
        return null;
    }

    @Override
    public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags) throws RemoteException {
        return null;
    }

    @Override
    public List<ResolveInfo> queryIntentActivities(Intent intent, String resolvedType, int flags) throws RemoteException {
        return null;
    }

    @Override
    public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags) throws RemoteException {
        return null;
    }

    @Override
    public ResolveInfo resolveService(Intent intent, String resolvedType, int flags) throws RemoteException {
        return null;
    }

    @Override
    public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags) throws RemoteException {
        return null;
    }

    @Override
    public List<ResolveInfo> queryIntentContentProviders(Intent intent, String resolvedType, int flags) throws RemoteException {
        return null;
    }

    @Override
    public List<PackageInfo> getInstalledPackages(int flags) throws RemoteException {
        return null;
    }

    @Override
    public List<ApplicationInfo> getInstalledApplications(int flags) throws RemoteException {
        return null;
    }

    @Override
    public PermissionInfo getPermissionInfo(String name, int flags) throws RemoteException {
        return null;
    }

    @Override
    public List<PermissionInfo> queryPermissionsByGroup(String group, int flags) throws RemoteException {
        return null;
    }

    @Override
    public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) throws RemoteException {
        return null;
    }

    @Override
    public List<PermissionGroupInfo> getAllPermissionGroups(int flags) throws RemoteException {
        return null;
    }

    @Override
    public ProviderInfo resolveContentProvider(String name, int flags) throws RemoteException {
        return null;
    }

    @Override
    public List<ActivityInfo> getReceivers(String packageName, int flags) throws RemoteException {
        return null;
    }

    @Override
    public List<IntentFilter> getReceiverIntentFilter(ActivityInfo info) throws RemoteException {
        return null;
    }

    @Override
    public int checkSignatures(String pkg1, String pkg2) throws RemoteException {
        return 0;
    }

    @Override
    public ActivityInfo selectStubActivityInfo(ActivityInfo targetInfo) throws RemoteException {
        return null;
    }

    @Override
    public ServiceInfo selectStubServiceInfo(ServiceInfo targetInfo) throws RemoteException {
        return null;
    }

    @Override
    public ServiceInfo selectStubServiceInfoByIntent(Intent targetIntent) throws RemoteException {
        return null;
    }

    @Override
    public ServiceInfo getTargetServiceInfo(ServiceInfo stubInfo) throws RemoteException {
        return null;
    }

    @Override
    public ProviderInfo selectStubProviderInfo(String name) throws RemoteException {
        return null;
    }

    @Override
    public List<String> getPackageNameByPid(int pid) throws RemoteException {
        return null;
    }

    @Override
    public String getProcessNameByPid(int pid) throws RemoteException {
        return null;
    }

    @Override
    public boolean killBackgroundProcesses(String packageName) throws RemoteException {
        return false;
    }

    @Override
    public boolean killApplicationProcess(String pluginPackageName) throws RemoteException {
        return false;
    }

    @Override
    public boolean forceStopPackage(String pluginPackageName) throws RemoteException {
        return false;
    }

    @Override
    public void onActivityCreated(ActivityInfo stubInfo, ActivityInfo targetInfo) throws RemoteException {
    }

    @Override
    public void onActivityDestory(ActivityInfo stubInfo, ActivityInfo targetInfo) throws RemoteException {
    }

    @Override
    public void onServiceCreated(ServiceInfo stubInfo, ServiceInfo targetInfo) throws RemoteException {
    }

    @Override
    public void onServiceDestory(ServiceInfo stubInfo, ServiceInfo targetInfo) throws RemoteException {
    }

    @Override
    public void onProviderCreated(ProviderInfo stubInfo, ProviderInfo targetInfo) throws RemoteException {
    }

    @Override
    public void onActivtyOnNewIntent(ActivityInfo stubInfo, ActivityInfo targetInfo, Intent intent) throws RemoteException {
    }

    @Override
    public int getMyPid() throws RemoteException {
        return 0;
    }
}
